package com.ebupt.migu.music.api.service.impl;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ebupt.migu.common.pojo.UserRelation;
import com.ebupt.migu.common.pojo.UserRelationRep;
import com.ebupt.migu.common.response.Response;
import com.ebupt.migu.common.response.ResponseBean;
import com.ebupt.migu.common.util.RestHttpUtil;
import com.ebupt.migu.music.api.entity.BannerApiResponse;
import com.ebupt.migu.music.api.entity.ContentInfo;
import com.ebupt.migu.music.api.entity.UserContentRequest;
import com.ebupt.migu.music.api.entity.UserContentResponse;
import com.ebupt.migu.music.api.mapper.BannerMapper;
import com.ebupt.migu.music.api.service.BannerService;
import com.ebupt.migu.music.api.util.CacheTask;
import com.ebupt.migu.music.api.util.ListUtils;
import com.ebupt.migu.music.common.api.ApiResponseConstans;
import com.ebupt.migu.music.common.constants.RedidKeyConstant;
import com.ebupt.migu.music.common.exception.MyException;
import com.ebupt.migu.music.common.exception.StatusEnum;
import com.ebupt.migu.music.common.util.ThreadPoolUtils;
import com.ebupt.migu.music.roster.entity.RosterBlackEntity;
import com.ebupt.migu.music.roster.entity.RosterWhiteEntity;
import com.ebupt.migu.music.roster.mapper.RosterMapper;
import com.ebupt.migu.music.schedule.mapper.PopupMapper;
import com.ebupt.migu.music.userGroup.entity.bo.UserGroupBo;
import com.ebupt.migu.music.userGroup.mapper.CrowdMapper;
import com.ebupt.migu.restapi.DownloadByFtp;
import com.ebupt.migu.restapi.RestHttpPost;
import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by Intellij IDEA.
 * User:  liuyangyang@cd.ebupt.com
 * Date:  2019/10/18
 */
@Slf4j
@Service
public class BannerServiceImpl implements BannerService {

    @Autowired
    private BannerMapper bannerMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private PopupMapper popupMapper;

    @Resource
    protected RosterMapper rosterMapper;
    @Resource
    protected CrowdMapper crowdMapper;

    @Value("${label.customer_match}")
    private String url;

    @Value("${fineOperationParent.old.usercontent}")
    private String oldUsercontentUrl;

    @Value("${label.post_url}")
    private String postUrl;

    @Value("${label.prefix}")
    private String prefix;



    @Override
    public BannerApiResponse usercontent(UserContentRequest userContentRequest) {
        BannerApiResponse response = new BannerApiResponse();
        long start = System.currentTimeMillis();
        if (null == userContentRequest) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("参数不可为空");
            return response;
        }
        if (StringUtils.isBlank(userContentRequest.getUserId()) || "00000000-0000-0000-0000-000000000000".equals(userContentRequest.getUserId())) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("user id不可为空");
            return response;
        }
        if (StringUtils.isBlank(userContentRequest.getUserStatus())) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("user status不可为空");
            return response;
        }
        if (!"0".equals(userContentRequest.getUserStatus()) && !"1".equals(userContentRequest.getUserStatus())) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("user status必须为0（已登录）或1（未登录）");
            return response;
        }
        if (null == userContentRequest.getTouchIds() || userContentRequest.getTouchIds().equals("")) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("touch id不可为空");
            return response;
        }
        String[] touchIDs = userContentRequest.getTouchIds();
        if (null == touchIDs || touchIDs.length == 0) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("touch id不可为空");
            return response;
        }
        List<String> ids = new ArrayList<>();
        List<Byte> stypes = new ArrayList<>();
        for (int i = 0; i < touchIDs.length; i++) {
            ids.add(touchIDs[i]);
        }
        // BANNER ：15030373
        if (ids.contains("31417313")) {
            stypes.add(Byte.valueOf("2"));
        }
        // 音乐之声 ：15044649
        if (ids.contains("31417432")) {
            stypes.add(Byte.valueOf("3"));
        }
        if (null == stypes || stypes.isEmpty()) {
            response.setData(null);
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_PARAMERROR);
            response.setRspdesc("touchids参数错误");
            return response;
        }

        UserContentResponse userContentResponse = new UserContentResponse();
        List<ContentInfo> contentInfos = new ArrayList<>();
        // 查询策略详情
        List<HashMap<String, Object>> strategys = bannerMapper.queryStrategyInfo(stypes);
        ContentInfo contentInfo;
        if (null != strategys && !strategys.isEmpty()) {
            if (strategys.size() > 5) {
                try {
                    contentInfos = exc(strategys, userContentRequest);
                }catch (ExecutionException e){
                    log.error("【查询banner时发生】线程执行异常");
                    e.printStackTrace();
                }catch ( InterruptedException e){
                    log.error("【查询banner时发生】中断异常");
                    e.printStackTrace();
                }
            } else {
                for (HashMap<String, Object> strategy : strategys) {
                    contentInfo = getContentInfo(strategy, userContentRequest);
                    if (null != contentInfo){
                        contentInfos.add(contentInfo);
                    }
                }
            }
        }
        userContentResponse.setContent(contentInfos);
        userContentResponse.setContentType(userContentRequest.getContentType());
        userContentResponse.setUserId(userContentRequest.getUserId());
        userContentResponse.setSessionId(userContentRequest.getSessionId());
        userContentResponse.setUserStatus(userContentRequest.getUserStatus());
        response.setData(userContentResponse);
        response.setRspcode(ApiResponseConstans.RESPONSE_CODE_SUCCESS);
        response.setRspdesc("查询成功");
        long end = System.currentTimeMillis();
        log.info("查询耗时：" + (end - start) + "毫秒");
        log.info("查询结果:{}", response.toString());
        if (userContentResponse.getContent().size() > 0) {
            log.info("参数{}有结果返回", userContentRequest.toString());
        } else {
            log.info("参数{}无结果返回", userContentRequest.toString());
        }
        return response;
    }

    /**
     * 判断当前用户是否在指定名单中
     *
     * @param id
     * @param uid
     * @return
     */
    private boolean isRosterMember(String id, String uid) {
        return bannerMapper.isRosterMember(id, uid);
    }

    /**
     * 定义返回内容
     *
     * @param contentInfos
     * @param contentInfo
     * @param strategy
     */
    private void setContentInfo(List<ContentInfo> contentInfos,
                                ContentInfo contentInfo,
                                HashMap<String, Object> strategy) {
        // 活动id
        contentInfo.setContentId(strategy.get("activityId").toString());
        // banner
        if ("2".equals(strategy.get("strategyType").toString())) {
            contentInfo.setIdx(Integer.valueOf(strategy.get("bannerPoint").toString()));
            contentInfo.setTouchId("31417313");
        }
        // 音乐之声
        if ("3".equals(strategy.get("strategyType").toString())) {
            contentInfo.setIdx(Integer.valueOf(strategy.get("musicPoint").toString()));
            contentInfo.setTouchId("31417432");
        }
        contentInfos.add(contentInfo);
    }

    private boolean sendCustomerMatch(String gid, String userId, String dataType) {
        log.info(">>>>>>>>>>进入统一标签平台验证客群是否存在接口发送：gid:{},userId:{},dataType:{}", gid, userId, dataType);
        UserRelation userRelation = new UserRelation();
        userRelation.setDataType(dataType);
        userRelation.setVal(userId);
        List<String> gidList = Lists.newArrayList();
        gidList.add(gid);
        userRelation.setCustomerIds(gidList);
        RestHttpPost post = new RestHttpPost();
        Response<String> rp = post.doRest(userRelation, url);
        if ("0000".equals(rp.getHead().getResponseCode())) {
            ResponseBean res = JSON.parseObject(rp.getResponse(), ResponseBean.class);
            if (null != res.getData()) {
                UserRelationRep rep = JSON.toJavaObject((JSON) res.getData(), UserRelationRep.class);
                List<String> reIds = rep.getCustomerIds();
                if (null != reIds && reIds.size() > 0) {
                    return true;
                }
            }
        }
        log.info(">>>>>>>>>>>>>>>>>>>>>在统一标签平台没有数据：gid:{},userId:{},dataType:{}", gid, userId, dataType);
        return false;
    }

    /**
     * 请求老系统的接口
     *
     * @param userContentRequest
     * @return
     */
    private List<ContentInfo> getOldUserContentResponse(UserContentRequest userContentRequest) {
        try {
            log.info(">>>>>>>>>>>>>>>>>>>向老系统发送请求，获取老系统数据，参数{}", userContentRequest.toString());
            String res = RestHttpUtil.doPost(oldUsercontentUrl, userContentRequest);
            log.info("<<<<<<<<<<<<<<<<<<<老系统返回结果为：{}", res);
            BannerApiResponse bannerApiResponse = JSON.parseObject(res, BannerApiResponse.class);
            if (ApiResponseConstans.RESPONSE_CODE_SUCCESS == bannerApiResponse.getRspcode()) {
                log.info("<<<<<<<<<<<<<<<<<<<老系统返回结果正确");
                res = bannerApiResponse.getData().toString();
                JSONObject jsonObject = JSON.parseObject(res);
                List<ContentInfo> contentInfos = (List<ContentInfo>) jsonObject.get("content");
                if (contentInfos.size() > 0) {
                    return contentInfos;
                }
            }
        } catch (Exception e) {
            log.error(">>>>>>>>>>>>>>请求老系统banner接口报错", e);
        }
        log.info("<<<<<<<<<<<<<<<<<<<老系统返回结果为空");
        return null;
    }

    @Override
    public BannerApiResponse getUserRelationVal(Map param) {
        BannerApiResponse response = new BannerApiResponse();
        try {
            File file = DownloadByFtp.getLabelUserGroup(param, prefix + postUrl, Integer.parseInt(param.get("dataType").toString()));
            if (null == file || file.length() == 0) {
                response.setRspcode(ApiResponseConstans.RESPONSE_CODE_SUCCESS);
                response.setRspdesc("查询成功,结果为空");
            }
            String msisdn = null;
            List<String> resultList = Lists.newArrayList();
            BufferedReader reader = new FileReader(file).getReader();
            int index = 0;
            while ((msisdn = reader.readLine()) != null && index < 10) {
                if (!"".equals(msisdn)) {
                    index++;
                    log.info(">>>>>>>>>>>>>>>当前值为{}", msisdn);
                    resultList.add(msisdn);
                }
            }
            reader.close();
            response.setRspcode(ApiResponseConstans.RESPONSE_CODE_SUCCESS);
            response.setRspdesc("查询成功");
            response.setData(resultList);
            return response;
        } catch (Exception e) {
            log.error("<<<<<<<<<<<<<<<<<<<获取统一标签平台客群中的值异常", e);
            throw new MyException(StatusEnum.ERROR, e.getMessage());
        }

    }

    /**
     *  优化线程池创建方式 直接获取执行任务
     * @param strategys
     * @param userContentRequest
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private List<ContentInfo> exc(List<HashMap<String, Object>> strategys, UserContentRequest userContentRequest) throws ExecutionException, InterruptedException {
        List<ContentInfo> contentInfos = Lists.newArrayList();
        List<Future<ContentInfo>> futureList = Lists.newArrayList();
        strategys.forEach(e -> {
            Future<ContentInfo> futureTask = ThreadPoolUtils.submit(new Callable<ContentInfo>() {
                @Override
                public ContentInfo call() throws Exception {
                    ContentInfo contentInfo = getContentInfo(e, userContentRequest);
                    return contentInfo;
                }
            });
            futureList.add(futureTask);
        });
        while (futureList.size() > 0) {
            Iterator<Future<ContentInfo>> iterator1 = futureList.iterator();
            while (iterator1.hasNext()) {
                Future<ContentInfo> future = iterator1.next();
                if (future.isDone() && !future.isCancelled()) {
                    ContentInfo value = future.get();
                    if (null != value) {
                        contentInfos.add(value);
                    }
                    iterator1.remove();
                }
            }
        }
        return contentInfos;
    }

    /**
     * 判断是否存在于白名单
     *
     * @return
     */
    protected Boolean isInblackList(String id, String uid) {
        String jsonString = (String) redisTemplate.opsForHash().get(RedidKeyConstant.BLACK_LIST_REDIS_KEY, id);
        Gson gson = new Gson();
        List<RosterBlackEntity> rosterBlackEntities = gson.fromJson(jsonString, new TypeToken<List<RosterBlackEntity>>() {
        }.getType());
        if (!redisTemplate.hasKey(RedidKeyConstant.BLACK_LIST_REDIS_KEY)) {
            List<RosterBlackEntity> rosterBlackEntityList = rosterMapper.getBlackListAll();
            Map<Long, List<RosterBlackEntity>> blackListMap = rosterBlackEntityList.stream().collect(Collectors.groupingBy(RosterBlackEntity::getRosterId));
            //存储
            blackListMap.forEach((key, value) -> {
                redisTemplate.opsForHash().put(RedidKeyConstant.BLACK_LIST_REDIS_KEY, String.valueOf(key), JSONUtil.toJsonStr(value));
            });
            redisTemplate.opsForHash().getOperations().expire(RedidKeyConstant.BLACK_LIST_REDIS_KEY, CacheTask.cacheTime, TimeUnit.MILLISECONDS);
            rosterBlackEntities = blackListMap.get(Long.parseLong(id));
        }
        Boolean result = false;
        if (null == rosterBlackEntities || rosterBlackEntities.isEmpty()) {
            return result;
        }
        for (RosterBlackEntity rosterBlackEntity : rosterBlackEntities) {
            if (uid.equals(rosterBlackEntity.getImei()) || uid.equals(rosterBlackEntity.getIdfa()) || uid.equals(rosterBlackEntity.getUuid())) {
                result = true;
                continue;
            }
        }
        return result;
    }


    /**
     * 判断是否存在于黑名单
     *
     * @return
     */
    protected Boolean isInWhiteList(String id, String uid) {
        String jsonString = (String) redisTemplate.opsForHash().get(RedidKeyConstant.WHITE_LIST_REDIS_KEY, id);
        Gson gson = new Gson();
        List<RosterWhiteEntity> rosterWhiteEntityList = gson.fromJson(jsonString, new TypeToken<List<RosterWhiteEntity>>() {
        }.getType());
        //  判断
        if (!redisTemplate.hasKey(RedidKeyConstant.WHITE_LIST_REDIS_KEY)) {
            List<RosterWhiteEntity> rosterWhiteEntityLists = rosterMapper.getWhiteListAll();
            Map<Long, List<RosterWhiteEntity>> whiteListMap = rosterWhiteEntityLists.stream().collect(Collectors.groupingBy(RosterWhiteEntity::getRosterId));
            //存储
            whiteListMap.forEach((key, value) -> {
                redisTemplate.opsForHash().put(RedidKeyConstant.WHITE_LIST_REDIS_KEY, String.valueOf(key), JSONUtil.toJsonStr(value));
            });
            redisTemplate.opsForHash().getOperations().expire(RedidKeyConstant.WHITE_LIST_REDIS_KEY, CacheTask.cacheTime, TimeUnit.MILLISECONDS);
            rosterWhiteEntityList = whiteListMap.get(Long.parseLong(id));
        }
        Boolean result = false;
        if (null == rosterWhiteEntityList || rosterWhiteEntityList.isEmpty()) {
            return result;
        }
        for (RosterWhiteEntity rosterWhiteEntity : rosterWhiteEntityList) {
            if (uid.equals(rosterWhiteEntity.getImei()) || uid.equals(rosterWhiteEntity.getIdfa()) || uid.equals(rosterWhiteEntity.getUuid())) {
                result = true;
                continue;
            }
        }
        return result;
    }

    /**
     *  判断是否动态客群
     * @param groupId
     * @return
     */
    protected Boolean isInGroup(String groupId){
        String bo = (String) redisTemplate.opsForHash().get(RedidKeyConstant.BANNER_GROUP_STATUS,groupId);
        if (!redisTemplate.hasKey(RedidKeyConstant.BANNER_GROUP_STATUS)) {
            List<UserGroupBo> userGroupBos = crowdMapper.selectStaticCustomerByAll();
            Map<String, Integer> userGroupBoMap = userGroupBos.stream().collect(Collectors.toMap(UserGroupBo::getGroupId, UserGroupBo::getIsStaticCustomer));
            //存储
            userGroupBoMap.forEach((key,value)->{
                redisTemplate.opsForHash().put(RedidKeyConstant.BANNER_GROUP_STATUS, key, value.toString());
            });
            redisTemplate.opsForHash().getOperations().expire(RedidKeyConstant.BANNER_GROUP_STATUS,CacheTask.cacheTime,TimeUnit.MILLISECONDS);
        }
        Boolean result = false;
        if ( StringUtils.isNoneBlank(bo) && bo.equals("1")){
            result = true;
        }
        return result;
    }

    protected ContentInfo getContentInfo(HashMap<String, Object> strategy, UserContentRequest userContentRequest) {
        ContentInfo contentInfo = new ContentInfo();
        String gid = strategy.get("groupId").toString();
        log.info("当前执行策略ID:{}, 人群ID:{}", strategy.get("strategyId"), gid);
        // 白名单： 1-添加白名单
        String[] white = null;
        // 黑名单： 1-剔除黑名单
        String[] black = null;
        if (null != strategy.get("white")) {
            // 多选白名单
            white = String.valueOf(strategy.get("white")).split(",");
        }
        if (null != strategy.get("black")) {
            // 多选黑名单
            black = String.valueOf(strategy.get("black")).split(",");
        }
        if (black != null && black.length > 0) {
            // 如果是黑名单用户，直接返回NULL
            boolean isMember = false;
            for (String id : black) {
                if (isInblackList(id, userContentRequest.getUserId())) {
                    isMember = true;
                    break;
                }
            }
            if (isMember) {
                return null;
            }
        }
        if (white != null && white.length > 0) {
            boolean isMember = false;
            // 如果是白名单用户，将活动信息返回
            for (String id : white) {
                if (isInWhiteList(id, userContentRequest.getUserId())) {
                    isMember = true;
                    break;
                }
            }
            if (isMember) {
                contentInfo =  backContentInfo(contentInfo, strategy);
                return contentInfo;
            }
        }
        // 通过UID登录
        if (userContentRequest.getUserStatus().equals("0")) {
            log.info(">>>>>>>>>>>>>>>>>>>>通过UID登录：gid:{}", gid);
            // smembers 查询全量元素
            // if (redisTemplate.opsForSet().members(gid + "-uid").contains(userContentRequest.getUserId())) {
            // sismember 查询指定元素是否在集合中
            // 判断用户群是否属于标签服务平台
            if (isInGroup(gid)) {
                log.info(">>>>>>>>>>>>>>>>>>>>>>是统一标签平台客群：gid:{}", gid);
                if (sendCustomerMatch(gid, userContentRequest.getUserId(), "3")) {
                    contentInfo = backContentInfo(contentInfo, strategy);
                }
            } else if (redisTemplate.opsForSet().isMember(gid + "-uid", userContentRequest.getUserId())) {
                contentInfo = backContentInfo(contentInfo, strategy);
            }
            return contentInfo;
        }
        // 通过IMEI/IDFA登录
        if (userContentRequest.getUserStatus().equals("1")) {
            log.info(">>>>>>>>>>>>>>>>>>>>通过IMEI/IDFA登录：gid:{}", gid);
            if (isInGroup(gid)) {
                log.info(">>>>>>>>>>>>>>>>>>>>>>是统一标签平台客群：gid:{}", gid);
                if (sendCustomerMatch(gid, userContentRequest.getUserId(), "2")) {
                    contentInfo = backContentInfo(contentInfo, strategy);
                }
            } else if (redisTemplate.opsForSet().isMember(gid + "-imei", userContentRequest.getUserId())) {
                contentInfo = backContentInfo(contentInfo, strategy);
            }
        }
        return contentInfo;
    }




    /**
     * 定义返回内容
     * @param contentInfo
     * @param strategy
     */
    private ContentInfo backContentInfo(ContentInfo contentInfo, HashMap<String, Object> strategy){
        // 活动id
        contentInfo.setContentId(strategy.get("activityId").toString());
        // banner
        if ("2".equals(strategy.get("strategyType").toString())) {
            contentInfo.setIdx(Integer.valueOf(strategy.get("bannerPoint").toString()));
            contentInfo.setTouchId("31417313");
        }
        // 音乐之声
        if ("3".equals(strategy.get("strategyType").toString())) {
            contentInfo.setIdx(Integer.valueOf(strategy.get("musicPoint").toString()));
            contentInfo.setTouchId("31417432");
        }
        return contentInfo;
    }

}
